package ru.lukyanets.transmission.client.action;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCombination;

/**
 * @author slukyanets
 */
public abstract class AbstractAction implements EventHandler<ActionEvent> {

    // --- disabled
    private final BooleanProperty disabledProperty = new SimpleBooleanProperty(this, "disabled"){ //$NON-NLS-1$
        @Override public void set(boolean value) {
            super.set(value);
        }
    };

    /**
     * This represents whether the action should be available to the end user,
     * or whether it should appeared 'grayed out'.
     *
     * @return An observable {@link BooleanProperty} that represents the current
     *      disabled state for this property, and which can be observed for
     *      changes.
     */
    public final BooleanProperty disabledProperty() {
        return disabledProperty;
    }

    /**
     *
     * @return whether the action is available to the end user,
     * or whether it should appeared 'grayed out'.
     */
    public final boolean isDisabled() {
        return disabledProperty.get();
    }

    /**
     * Sets whether the action should be available to the end user,
     * or whether it should appeared 'grayed out'.
     * @param value - state
     */
    public final void setDisabled(boolean value) {
        disabledProperty.set(value);
    }


    // --- accelerator
    private final ObjectProperty<KeyCombination> acceleratorProperty = new SimpleObjectProperty<>(this, "accelerator") { //$NON-NLS-1$
        @Override
        public void set(KeyCombination value) {
            super.set(value);
        }
    };

    /**
     * The accelerator {@link KeyCombination} that should be used for this action,
     * if it is used in an applicable UI control (most notably {@link MenuItem}).
     *
     * @return An observable {@link ObjectProperty} that represents the current
     *      accelerator for this property, and which can be observed for changes.
     */
    public final ObjectProperty<KeyCombination> acceleratorProperty() {
        return acceleratorProperty;
    }

    /**
     *
     * @return The accelerator {@link KeyCombination} that should be used for this action,
     * if it is used in an applicable UI control
     * @noinspection unused
     */
    public final KeyCombination getAccelerator() {
        return acceleratorProperty.get();
    }

    /**
     * Sets the accelerator {@link KeyCombination} that should be used for this action,
     * if it is used in an applicable UI control
     * @param value - key combination
     */
    public final void setAccelerator(KeyCombination value) {
        acceleratorProperty.set(value);
    }

    /**
     * Handles fired event
     * @param event - ActionEvent to be handled
     */
    @Override
    public final void handle(ActionEvent event) {
        if (!isDisabled()) {
            performAction(event);
        }
    }

    /**
     * Performs concrete action
     * @param event - ActionEvent to be handled
     */
    protected abstract void performAction(ActionEvent event);

    //--- helper methods for UI

    /**
     * Configure menuItem for action properties
     * @param menuItem to be configured
     */
    public <T extends MenuItem> void configure(final T menuItem) {
        menuItem.disableProperty().bind(disabledProperty());
        menuItem.acceleratorProperty().bind(acceleratorProperty());
        menuItem.setOnAction(this);
    }

    /**
     * Configure button for action properties
     * @param button to be configured
     */
    public <T extends ButtonBase> void configure(final T button) {
        button.disableProperty().bind(disabledProperty());
        button.setOnAction(this);
    }
}
